﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using Microsoft.Surface;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;

using ESRI.ArcGIS.Client.Geometry;

namespace ENMAX_ArcGIS
{
    /// <summary>
    /// Interaction logic for TroubleTicketListFrame.xaml.  This
    /// is a ScatterViewItem that contains a list of TroubleTickets.
    /// </summary>
    public partial class TroubleTicketListFrame : ScatterViewItem
    {
        private TwoPointScatterView parent;

        public ItemCollection TroubleTicketListItems
        {
            get
            {
                return Content.Items;
            }
        }

        /// <summary>
        /// Creates a TroubleTicketListFrame.  It takes a reference of 
        /// the TwoPointScatterView (where the frame itself exists),
        /// a Point (where the frame should appear in the ScatterView),
        /// and the orientation of the frame itself.
        /// </summary>
        /// <param name="tpScatterView"></param>
        /// <param name="pt"></param>
        /// <param name="orientation"></param>
        public TroubleTicketListFrame(TwoPointScatterView tpScatterView, Point pt, double orientation)
        {
            InitializeComponent();
            parent = tpScatterView;
            PopulateDemoList();
            this.Center = pt;
            this.Orientation = orientation;

        }

        /// <summary>
        /// Closes this TroubleTicketListFrame by
        /// removing it from view.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Close_Button_Click(object sender, RoutedEventArgs e)
        {
            parent.RemoveTroubleTicketListFrame(this);
        }

        /// <summary>
        /// Removes a TroubleTicket from the TroubleTicketList
        /// </summary>
        /// <param name="tTicket"></param>
        public void RemoveTroubleTicketItem(TroubleTicketListItem deleteItem)
        {
            if (Content.Items.Contains(deleteItem))
                Content.Items.Remove(deleteItem);
        }

        /// <summary>
        /// This is used only for demo purpose.
        /// It populates the the TroubleTicketList with
        /// some imaginary TroubleTickets.
        /// </summary>
        private void PopulateDemoList()
        {
            Envelope env1 = new Envelope(-114.15691902877, 51.0591195173411, -114.1102425907428, 51.0835361218838);
            TroubleTicket t1 = new TroubleTicket(env1, "Customer Service Request 1324", "0006789", TroubleTicket.TroubleTicketSeverity.High);
            this.AddTroubleTicket(t1);

            Envelope env2 = new Envelope(-113.99015924813, 51.0683510952592, -113.971690916148, 51.0779038238194);
            TroubleTicket t2 = new TroubleTicket(env2, "Emergency Service Request", "0006788", TroubleTicket.TroubleTicketSeverity.Medium);
            this.AddTroubleTicket(t2);

            Envelope env3 = new Envelope(-114.040546984042, 51.0594606891567, -114.022078375376, 51.0690134177768);
            TroubleTicket t3 = new TroubleTicket(env3, "Power Outage zone 321", "0006789", TroubleTicket.TroubleTicketSeverity.High);
            this.AddTroubleTicket(t3);

            Envelope env4 = new Envelope(-114.09213171891, 50.9930501197892, -114.073663109925, 51.0026028484093);
            TroubleTicket t4 = new TroubleTicket(env4, "Underground wire repair", "0006789", TroubleTicket.TroubleTicketSeverity.Low);
            this.AddTroubleTicket(t4);

            Envelope env5 = new Envelope(-114.21407548367, 51.0142953882404, -114.195606875005, 51.0238481168606);
            TroubleTicket t5 = new TroubleTicket(env5, "Customer Service Request 4231", "0006789", TroubleTicket.TroubleTicketSeverity.High);
            this.AddTroubleTicket(t5);

            Envelope env6 = new Envelope(-114.184245496432, 51.0005649329704, -114.164776887767, 51.0101176615905);
            TroubleTicket t6 = new TroubleTicket(env6, "New transformer installation", "0006789", TroubleTicket.TroubleTicketSeverity.Low);
            this.AddTroubleTicket(t6);

            Envelope env7 = new Envelope(-114.15691902877, 51.0591195173411, -114.1102425907428, 51.0835361218838);
            TroubleTicket t7 = new TroubleTicket(env7, "Power Outage zone 982", "0006789", TroubleTicket.TroubleTicketSeverity.High);
            this.AddTroubleTicket(t7);

            Envelope env8 = new Envelope(-114.17533407931, 51.0654470657586, -114.157064799265, 51.074999793788);
            TroubleTicket t8 = new TroubleTicket(env8, "Customer Service Request 0093", "0006789", TroubleTicket.TroubleTicketSeverity.Medium);
            this.AddTroubleTicket(t8);

            Envelope env9 = new Envelope(-133.99015924813, 51.0683510952592, -133.971690916148, 51.0779038238194);
            TroubleTicket t9 = new TroubleTicket(env9, "New wire installation", "0006789", TroubleTicket.TroubleTicketSeverity.Medium);
            this.AddTroubleTicket(t9);
        }

        /// <summary>
        /// Event handler when an item (TroubleTicket) is tapped in the
        /// TroubleTicketList.  When this happens, a MapFrame representing
        /// the tapped TroubleTicket appears.  We also calculate where this
        /// MapFrame should appear.  The MapFrame should be close to the
        /// TroubleTicketList.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void TroubleTicketListContactTap(object sender, ContactEventArgs e)
        {
            TroubleTicketListItem touchedTicketItem = sender as TroubleTicketListItem;
            TroubleTicket touchedTicket = touchedTicketItem.TroubleTicket;
            Point centrePoint = this.Center;

            /* Calculate where the map frame should go */

            /* by default, the map frame would appear in the centre of the screen */
            Point result = new Point(384, 512);
            Point leftPt = new Point(0, 0);
            Point topPt = new Point(0, 0);
            Point rightPt = new Point(0, 0);
            Point btmPt = new Point(0, 0);

            /* The position of the map frame depends on the orientation
             * of the trouble ticket list itself
             */
            if (this.Orientation >= 270 && this.Orientation < 360)
            {
                double radian = Math.PI * (Math.Abs(this.Orientation - 360)) / 180.0;
                double y = Math.Sin(radian) * ( 20 + touchedTicket.MapFrameWidth);
                double x = Math.Cos(radian) * ( 20 + touchedTicket.MapFrameWidth);
                leftPt = new Point(this.Center.X - x, this.Center.Y + y);
                result = leftPt;

                if (OutOfBounds(leftPt))
                {
                    x = Math.Sin(radian) * (20 + touchedTicket.MapFrameHeight);
                    y = Math.Cos(radian) * (20 + touchedTicket.MapFrameHeight);
                    topPt = new Point(this.Center.X - x, this.Center.Y - y);
                    result = topPt;
                    
                    if (OutOfBounds(topPt))
                    {
                        y = Math.Sin(radian) * (20 + touchedTicket.MapFrameWidth);
                        x = Math.Cos(radian) * (20 + touchedTicket.MapFrameWidth);
                        rightPt = new Point(this.Center.X + x, this.Center.Y - y);
                        result = rightPt;

                        if (OutOfBounds(rightPt))
                        {
                            x = Math.Sin(radian) * (20 + touchedTicket.MapFrameHeight);
                            y = Math.Cos(radian) * (20 + touchedTicket.MapFrameHeight);
                            btmPt = new Point(this.Center.X + x, this.Center.Y + y);
                            result = btmPt;
                        }
                    }
                }

            }
            if (this.Orientation >= 0 && this.Orientation < 90)
            {
                double radian = Math.PI * this.Orientation / 180.0;
                double y = Math.Sin(radian) * (20 + touchedTicket.MapFrameWidth);
                double x = Math.Cos(radian) * (20 + touchedTicket.MapFrameWidth);
                leftPt = new Point(this.Center.X - x, this.Center.Y - y);
                result = leftPt;

                if (OutOfBounds(leftPt))
                {
                    x = Math.Sin(radian) * (touchedTicket.MapFrameHeight);
                    y = Math.Cos(radian) * (touchedTicket.MapFrameHeight);
                    topPt = new Point(this.Center.X + x, this.Center.Y - y);
                    result = topPt;
                    if (OutOfBounds(topPt))
                    {
                        y = Math.Sin(radian) * (20 + touchedTicket.MapFrameWidth);
                        x = Math.Cos(radian) * (20 + touchedTicket.MapFrameWidth);
                        rightPt = new Point(this.Center.X + x, this.Center.Y + y);
                        result = rightPt;

                        if (OutOfBounds(rightPt))
                        {
                            x = Math.Sin(radian) * (touchedTicket.MapFrameHeight);
                            y = Math.Cos(radian) * (touchedTicket.MapFrameHeight);
                            btmPt = new Point(this.Center.X - x, this.Center.Y + y);
                            result = btmPt;
                        }
                    }
                }
                
            }
            if (this.Orientation >= 90 && this.Orientation < 180)
            {
                double radian = Math.PI * (Math.Abs(this.Orientation - 180)) / 180.0;
                double y = Math.Sin(radian) * (20 + touchedTicket.MapFrameWidth);
                double x = Math.Cos(radian) * (20 + touchedTicket.MapFrameWidth);
                leftPt = new Point(this.Center.X + x, this.Center.Y - y);
                result = leftPt;

                if (OutOfBounds(leftPt))
                {
                    x = Math.Sin(radian) * (touchedTicket.MapFrameHeight);
                    y = Math.Cos(radian) * (touchedTicket.MapFrameHeight);
                    topPt = new Point(this.Center.X + x, this.Center.Y + y);
                    result = topPt;
                    if (OutOfBounds(topPt))
                    {
                        y = Math.Sin(radian) * (20 + touchedTicket.MapFrameWidth);
                        x = Math.Cos(radian) * (20 + touchedTicket.MapFrameWidth);
                        rightPt = new Point(this.Center.X - x, this.Center.Y + y);
                        result = rightPt;

                        if (OutOfBounds(rightPt))
                        {
                            x = Math.Sin(radian) * (touchedTicket.MapFrameHeight);
                            y = Math.Cos(radian) * (touchedTicket.MapFrameHeight);
                            btmPt = new Point(this.Center.X - x, this.Center.Y - y);
                            result = btmPt;
                        }
                    }
                }
            }
            if (this.Orientation >= 180 && this.Orientation < 270)
            {
                double radian = Math.PI * (Math.Abs(this.Orientation - 360)) / 180.0;
                double y = Math.Sin(radian) * (20 + touchedTicket.MapFrameWidth);
                double x = Math.Abs(Math.Cos(radian) * (20 + touchedTicket.MapFrameWidth));
                leftPt = new Point(this.Center.X - x, this.Center.Y + y);
                result = leftPt;

                if (OutOfBounds(leftPt))
                {
                    x = Math.Sin(radian) * (touchedTicket.MapFrameHeight);
                    y = Math.Abs(Math.Cos(radian) * (touchedTicket.MapFrameHeight));
                    topPt = new Point(this.Center.X - x, this.Center.Y + y);
                    result = topPt;
                    if (OutOfBounds(topPt))
                    {
                        y = Math.Sin(radian) * (20 + touchedTicket.MapFrameWidth);
                        x = Math.Abs(Math.Cos(radian) * (20 + touchedTicket.MapFrameWidth));
                        rightPt = new Point(this.Center.X - x, this.Center.Y - y);
                        result = rightPt;

                        if (OutOfBounds(rightPt))
                        {
                            x = Math.Sin(radian) * (touchedTicket.MapFrameHeight);
                            y = Math.Abs(Math.Cos(radian) * (touchedTicket.MapFrameHeight));
                            btmPt = new Point(this.Center.X + x, this.Center.Y - y);
                            result = btmPt;
                        }
                    }
                }
            }

            parent.CreateMapFrameFromTroubleTicketList(touchedTicket, result, this.Orientation-90);

            
        }

        /// <summary>
        /// Adds a TroubleTicket item to the TroubleTicketList
        /// </summary>
        /// <param name="inputTicket"></param>
        public TroubleTicketListItem AddTroubleTicket(TroubleTicket inputTicket)
        {
            TroubleTicketListItem inputItem = new TroubleTicketListItem(inputTicket);
            inputItem.ContactTapGesture += new ContactEventHandler(TroubleTicketListContactTap);
            Content.Items.Add(inputItem);

            //used for unit tests
            return inputItem;
        }

        public void AddTroubleTicket(TroubleTicketListItem inputItem)
        {
            inputItem.ContactTapGesture += new ContactEventHandler(TroubleTicketListContactTap);
            Content.Items.Add(inputItem);
        }

        /// <summary>
        /// Determines if a point is outside the
        /// acceptable bounds of the screen.
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        private bool OutOfBounds(Point pt)
        {
            return pt.X < 200 || pt.X > 600|| pt.Y < 200 || pt.Y > 800;
        }
    }
}
